package com.aabte.lota.auth.auth.controller;

import com.aabte.commons.rest.api.ApiResult;
import com.aabte.commons.rest.exception.ApiException;
import com.aabte.lota.auth.auth.bean.constant.LoginConstants;
import com.aabte.lota.auth.auth.bean.enums.LoginApiErrorCode;
import com.aabte.lota.auth.auth.bean.query.LoginQuery;
import com.aabte.lota.auth.auth.service.LoginService;
import com.aabte.lota.auth.auth.token.JWTTokenResult;
import com.aabte.lota.auth.auth.token.JWTTokenUtils;
import com.aabte.lota.auth.auth.token.exception.TokenException;
import com.aabte.lota.auth.auth.token.payload.TokenPayloadDTO;
import com.aabte.lota.auth.common.util.ServletUtils;
import javax.annotation.Resource;
import javax.validation.Valid;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.authz.annotation.RequiresGuest;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author Daniel
 * @version 1.0
 * @date 2020/4/5
 */
@RestController
@RequestMapping(path = "/v1/login")
public class LoginController {

  @Resource private LoginService loginService;

  @Resource private JWTTokenUtils jwtTokenUtils;

  @RequiresGuest
  @PostMapping(path = "/token")
  public ApiResult<TokenPayloadDTO> login(@RequestBody @Valid LoginQuery loginQuery) {
    try {
      JWTTokenResult jwtTokenResult = loginService.login(loginQuery);
      TokenPayloadDTO tokenPayload = jwtTokenResult.getTokenPayload();
      ServletUtils.setResponseHeader(
          LoginConstants.HEADER_NAME_AUTHORIZATION, jwtTokenResult.getToken());
      return ApiResult.ok(tokenPayload);
    } catch (UnknownAccountException | IncorrectCredentialsException e) {
      throw new ApiException(LoginApiErrorCode.USERNAME_OR_PASSWORD_INCORRECT, e);
    } catch (LockedAccountException e) {
      throw new ApiException(LoginApiErrorCode.LOCKED_ACCOUNT, e);
    } catch (ExcessiveAttemptsException e) {
      throw new ApiException(LoginApiErrorCode.EXCESSIVE_ATTEMPTS, e);
    } catch (AuthenticationException e) {
      throw new ApiException(LoginApiErrorCode.LOGIN_FAILED, e);
    }
  }

  @RequiresAuthentication
  @RequestMapping(path = "/me", method = RequestMethod.GET)
  public ApiResult<TokenPayloadDTO> me() {
    String jwtToken = ServletUtils.getJwtToken();
    TokenPayloadDTO tokenPayload;
    try {
      tokenPayload = jwtTokenUtils.parseToken(jwtToken);
    } catch (TokenException e) {
      throw new ApiException(LoginApiErrorCode.TOKEN_INCORRECT);
    }
    return ApiResult.ok(tokenPayload);
  }
}
